module queueOutSide (   //我现在的立场是在输出端口处
    input       wire              clk                       ,
    input       wire              rst                       ,
    // 入队所需信息
    input       wire              enqueue_en                ,       //压栈使能
    input       wire     [5:0]    enqueue_priority          ,       //数据包优先级
    input       wire     [15:0]   enqueue_value             ,       //数据包地址（RAM块号6位+块内地址10位）
    // 出队指示信息 + 更新队头信息
    input       wire              port_out_idle             ,       //输出端口是否空闲，空闲则可进行输出;port_out_idle初始化值应为1
    input       wire              dequeue_head_update_en    ,       //出栈更新队头使能
    input       wire     [5:0]    dequeue_head_priority     ,       //新队头优先级
    input       wire     [15:0]   dequeue_head_new          ,       //新队头地址
    // 入队使能，寻址老地址，写入新地址
    output      reg               enqueue_sucess            ,       //写入成功信号
    output      reg               enqueue_update_en         ,
    output      reg      [5:0]    enqueue_update_priority   ,
    output      reg      [7:0]    is_first_tail             ,       //判断是否为此队列的第一个元素
    output      reg      [15:0]   enqueue_tail_old          ,       //老队尾（找到老队尾，并通知其新队尾的地址信息）
    output      reg      [15:0]   enqueue_tail_new          ,       //新队尾（用于与老队尾添加链接关系）
    // 出队有效 + 判定队列count状态，若此时队列只有一个元素，则无需反馈；否则需要反馈
    output      reg               dequeue_vld               ,       //出栈使能
    output      reg      [5:0]    dequeue_priority          ,       //出队优先级
    output      reg      [7:0]    is_last_head              ,       //判断是否为此队列的最后一个元素
    output      reg      [15:0]   dequeue_head_old                  //出栈老队头
);
    //维护头尾指针
    reg     [15:0]      head       [7:0]    ;           //每个端口有8个虚拟的优先级队列，并且有一个count数组进行计数
    reg     [15:0]      tail       [7:0]    ;           //假设所有存储空间都存储64B的最短包，并且都往同一个端口的同一个优先级队列转发，
    reg     [13:0]      count      [7:0]    ;           //那么最长就会有32*256Kb/8/64B = 16384，即2的14次方
    reg                 last_port_out_idle  ;
    reg                 port_free           ;
    wire    [3:0]       strict_pri_order    ;
    integer i;
    
    always @(posedge clk or negedge rst) begin   //数组初始化
        if (rst) begin
            for(i = 0; i < 8; i = i + 1) begin
                head[i]  <= 16'h0000;
                tail[i]  <= 16'h0000;
                count[i] <= 14'd0000;
            end
            enqueue_sucess   <= 1'b0;
            is_first_tail    <= 8'b0000_0000;
            is_last_head     <= 8'b0000_0000;
            dequeue_head_old <= 16'h0000;   
            enqueue_tail_old <= 16'h0000;
            enqueue_tail_new <= 16'h0000;
        end                                     //1）入队压栈（因为不是随时都可以压栈的，需要进行仲裁后才可以）
        else if (enqueue_en) begin              //找到对应优先级队列的队尾元素，首先对老队尾元素进行保存，然后用新队尾元素进行替换
            if (port_free && (enqueue_priority == strict_pri_order)) begin
                enqueue_sucess <= 1'b0;
            end
            else begin
                if (count[enqueue_priority] == 'd0) begin
                    is_first_tail[enqueue_priority] <= 1'b1;          //如果为1，则建立对应队列的新列
                    head[enqueue_priority] <= enqueue_value;          //此时，队头和队尾重合，因此，既要更新队头，也要更新队尾
                    enqueue_tail_old <= enqueue_value;
                end
                else begin
                    is_first_tail[enqueue_priority] <= 1'b0;          //队尾修改后，队列这部分其实已经完成，无需后续后操
                    //释放更新信号                                     //不过需要把老队尾和新队尾数据传输出去，对表进行修改
                    enqueue_tail_old <= tail[enqueue_priority];       
                    enqueue_tail_new <= enqueue_value;
                end
                //更新尾指针
                tail[enqueue_priority]  <= enqueue_value;
                count[enqueue_priority] <= count[enqueue_priority] + 1'b1;
                enqueue_sucess <= 1'b1;
            end
        end
        else begin
            enqueue_sucess <= 1'b0;
        end
    end

    assign strict_pri_order = count[0] > 0 ? 'd0 :
                              count[1] > 0 ? 'd1 :
                              count[2] > 0 ? 'd2 :
                              count[3] > 0 ? 'd3 :
                              count[4] > 0 ? 'd4 :
                              count[5] > 0 ? 'd5 :
                              count[6] > 0 ? 'd6 :
                              count[7] > 0 ? 'd7 :
                              'b1111;

    //记录输出端口状态的跳变信息
    always @(posedge clk or negedge rst) begin              
        if (rst) begin
            last_port_out_idle <= 1'b1;   
            port_free <= 1'b1;
            dequeue_vld <= 1'b0;                      
        end
        else begin
            last_port_out_idle <= port_out_idle;    
            if (last_port_out_idle == 1'b0 && port_out_idle == 1'b1) begin  //输出端口前一个clk状态为忙，后一个状态为空闲时，表示可输出
                port_free <= 1'b1;
            end
        end
    end

    //出队逻辑，出队之后，得等其返回新的队头
    always @(posedge clk) begin
        if (port_free == 1'b1 && strict_pri_order != 'b1111) begin       //可出栈并且队列非空，
            dequeue_vld <= 1'b1;
            dequeue_head_old <= head[strict_pri_order];
            if (count[strict_pri_order] == 'd1) begin       //队列中最后一个元素，则无需返回新的队头或队尾
                is_last_head[strict_pri_order] = 1'b1;
            end
            count[strict_pri_order] <= count[strict_pri_order] - 1'b1;
            port_free <= 1'b0;      
        end

        if (port_free == 1'b0) begin
            dequeue_vld <= 1'b0;
        end
    end

    always @(posedge clk) begin
        if (dequeue_head_update_en) begin
            //更新队列头元素
            head[dequeue_head_priority] <= dequeue_head_new;
        end
    end
endmodule